package jnpf.database.config;

import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.annotation.DbType;
import com.baomidou.mybatisplus.autoconfigure.SpringBootVFS;
import com.baomidou.mybatisplus.core.MybatisConfiguration;
import com.baomidou.mybatisplus.core.config.GlobalConfig;
import com.baomidou.mybatisplus.core.incrementer.IKeyGenerator;
import com.baomidou.mybatisplus.core.injector.ISqlInjector;
import com.baomidou.mybatisplus.extension.incrementer.H2KeyGenerator;
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.handler.TableNameHandler;
import com.baomidou.mybatisplus.extension.plugins.inner.DynamicTableNameInnerInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
import jnpf.config.ConfigValueUtil;
import jnpf.database.data.DataSourceContextHolder;
import jnpf.util.DataSourceUtil;
import jnpf.util.DbConUtil;
import jnpf.base.DbTableConModel;
import jnpf.util.JdbcUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.logging.slf4j.Slf4jImpl;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.type.JdbcType;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.core.io.support.ResourcePatternResolver;

import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;

@Slf4j
@Configuration
@ComponentScan("jnpf")
@MapperScan(basePackages = {"jnpf.*.mapper","jnpf.mapper"})
public class MybatisPlusConfig{

    /**
     * 对接数据库的实体层
     */
    static final String ALIASES_PACKAGE = "jnpf.*.entity";



    @Autowired
    private DataSourceUtil dataSourceUtil;
    @Autowired
    private ConfigValueUtil configValueUtil;

    @Primary
    @Bean(name = "dataSourceSystem")
    public DataSource dataSourceOne(Environment env) {
        String prefix = "spring.datasource.druid.";
        return druidDataSource(env, prefix);
    }

    @Bean(name = "sqlSessionFactorySystem")
    public SqlSessionFactory sqlSessionFactoryOne(@Qualifier("dataSourceSystem") DataSource dataSource) throws Exception {
        return createSqlSessionFactory(dataSource);
    }

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        //

        //判断是否多租户
        if (Boolean.parseBoolean(configValueUtil.getMultiTenancy())) {
            DynamicTableNameInnerInterceptor dynamicTableNameInnerInterceptor = new DynamicTableNameInnerInterceptor();
            HashMap<String, TableNameHandler> map = new HashMap<>(150) ;
            String url=dataSourceUtil.getUrl().replace("{dbName}", dataSourceUtil.getDbInit());
            Connection conn = JdbcUtil.getConn(dataSourceUtil.getUserName(), dataSourceUtil.getPassword(), url);
            List<DbTableConModel> dbTableModels=new ArrayList<>();
            if (conn != null) {
                if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.MYSQL.getDb())) {
                    dbTableModels = DbConUtil.mysqlgetList(conn, dataSourceUtil.getDbInit());
                } else if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.SQL_SERVER.getDb())) {
                    dbTableModels = DbConUtil.sqlServergetList(conn, dataSourceUtil.getDbInit());
                } else if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.ORACLE.getDb())) {
                    dbTableModels = DbConUtil.orcalgetList(conn, dataSourceUtil.getDbInit());
                }else if(dataSourceUtil.getDataType().toLowerCase().equals(DbType.DM.getDb())){
                    dbTableModels = DbConUtil.dmgetList(conn, dataSourceUtil.getDbInit());
                }
            }
            log.error("con:"+conn);
            for(DbTableConModel dbTableModel:dbTableModels){
                if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.MYSQL.getDb())) {
                    map.put(dbTableModel.getTable(), (sql, tableName) -> DataSourceContextHolder.getDatasourceName()+"."+dbTableModel.getTable());
                } else if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.SQL_SERVER.getDb())) {
                    map.put(dbTableModel.getTable(), (sql, tableName) -> DataSourceContextHolder.getDatasourceName()+".dbo."+dbTableModel.getTable());
                } else if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.ORACLE.getDb())) {
                    map.put(dbTableModel.getTable().toLowerCase(), (sql, tableName) -> DataSourceContextHolder.getDatasourceName().toUpperCase()+"."+dbTableModel.getTable());
                }else if(dataSourceUtil.getDataType().toLowerCase().equals(DbType.DM.getDb())){
                    map.put(dbTableModel.getTable(), (sql, tableName) -> DataSourceContextHolder.getDatasourceName()+"."+dbTableModel.getTable());
                }
            }
            dynamicTableNameInnerInterceptor.setTableNameHandlerMap(map);
            interceptor.addInnerInterceptor(dynamicTableNameInnerInterceptor);
            }
        //新版本分页必须指定数据库，否则分页不生效
        if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.MYSQL.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
        } else if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.SQL_SERVER.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.SQL_SERVER));
        } else if (dataSourceUtil.getDataType().toLowerCase().equals(DbType.ORACLE.getDb())) {
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.ORACLE));
        }else if(dataSourceUtil.getDataType().toLowerCase().equals(DbType.DM.getDb())){
            interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.DM));
        }
        return interceptor;
    }


    protected DataSource druidDataSource(Environment env, String prefix) {
        String url;
        if (Boolean.parseBoolean(configValueUtil.getMultiTenancy())) {
            String dbNull = env.getProperty(prefix + "dbnull");
            url = env.getProperty(prefix + "url").replace("{dbName}", dbNull);
        }else{
            String dbName = env.getProperty(prefix + "dbname");
            url = env.getProperty(prefix + "url").replace("{dbName}", dbName);
        }
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setUsername(env.getProperty(prefix + "username"));
        dataSource.setUrl(url);
        dataSource.setPassword(env.getProperty(prefix + "password"));
        dataSource.setDriverClassName(env.getProperty(prefix + "driver-class-name"));
        return dataSource;
    }

    public Resource[] resolveMapperLocations() {
        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        List<String> mapperLocations = new ArrayList<>();
        mapperLocations.add("classpath*:mapper/*.xml");
        mapperLocations.add("classpath*:mapper/*/*.xml");
        mapperLocations.add("classpath*:mapper/*/*/*.xml");
        List<Resource> resources = new ArrayList();
        if (mapperLocations != null) {
            for (String mapperLocation : mapperLocations) {
                try {
                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
                    resources.addAll(Arrays.asList(mappers));
                } catch (IOException e) {
                    // ignore
                }
            }
        }
        return resources.toArray(new Resource[resources.size()]);
    }

    public SqlSessionFactory createSqlSessionFactory(DataSource dataSource) throws Exception {
        MybatisSqlSessionFactoryBean bean = new MybatisSqlSessionFactoryBean();
        bean.setDataSource(dataSource);
        //全局配置
        GlobalConfig globalConfig = new GlobalConfig();
        //配置填充器
        globalConfig.setMetaObjectHandler(new MybatisPlusMetaObjectHandler());
        bean.setGlobalConfig(globalConfig);

        bean.setVfs(SpringBootVFS.class);
        bean.setTypeAliasesPackage(ALIASES_PACKAGE);
        bean.setMapperLocations(resolveMapperLocations());
        bean.setConfiguration(configuration(dataSource));
        return bean.getObject();
    }

    public MybatisConfiguration configuration(DataSource dataSource){
        MybatisConfiguration mybatisConfiguration = new MybatisConfiguration();
        mybatisConfiguration.setMapUnderscoreToCamelCase(true);
        mybatisConfiguration.setCacheEnabled(false);
        mybatisConfiguration.addInterceptor(mybatisPlusInterceptor());
        mybatisConfiguration.setLogImpl(Slf4jImpl.class);
        mybatisConfiguration.setJdbcTypeForNull(JdbcType.NULL);
        return mybatisConfiguration;
    }
    @Bean
    public IKeyGenerator keyGenerator() {
        return new H2KeyGenerator();
    }

    @Bean
    public ISqlInjector sqlInjector() {
        return (builderAssistant, mapperClass) -> {

        };
    }

    /**
     * 数据权限插件
     *
     * @return DataScopeInterceptor
     */
//    @Bean
//    @ConditionalOnMissingBean
//    public DataScopeInterceptor dataScopeInterceptor(DataSource dataSource) {
//        return new DataScopeInterceptor(dataSource);
//    }

}
